.386
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
include \masm32\include\fpu.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\fpu.lib


PrintAndRead macro text:REQ, buffer:REQ
    invoke StdOut, text
    invoke StdIn, ADDR buffer, LengthOf buffer
endm


PrintSt0 macro
    invoke FpuFLtoA, 0, 10, addr buf, SRC1_FPU or SRC2_DIMM
    invoke StdOut, addr buf
endm

PrintSt0Integer macro
    invoke FpuFLtoA, 0, 0, addr buf, SRC1_FPU or SRC2_DIMM
    invoke StdOut, addr buf
endm

.const
    one dt 1.0
    two dq 2.0
    three dt 3.0
    four dt 4.0
    Spaces db ' ', ' ', ' ', 0
    NewLine db 10, 13, 0
    EnterA db "Enter a: ", 0
    EnterB db "Enter b: ", 0
    EnterH db "Enter h: ", 0
    EnterEps db "Enter epsilon: ", 0
    ConversionError db "Cannot convert between string and real", 10, 13, 0


.data?
    a dt ?
    b dt ?
    h dt ?
    eps dt ?
    tmp dt ?
    tmp1 dt ?
    tmp2 dt ?
    tmp3 dt ?
    counter dt ?

.data
    buf db 64 dup (0)

 
.code
ReadInput proc
    PrintAndRead ADDR EnterA, buf
    invoke FpuAtoFL, ADDR buf, ADDR a, DEST_MEM     ; pushing to the FPU stack
    cmp eax, 0
    je conv_err

    PrintAndRead ADDR EnterB, buf
    invoke FpuAtoFL, ADDR buf, ADDR b, DEST_MEM     ; pushing to the FPU stack
    cmp eax, 0
    je conv_err

    PrintAndRead ADDR EnterH, buf
    invoke FpuAtoFL, ADDR buf, ADDR h, DEST_MEM     ; pushing to the FPU stack
    cmp eax, 0
    je conv_err
    
    PrintAndRead ADDR EnterEps, buf
    invoke FpuAtoFL, ADDR buf, ADDR eps, DEST_MEM     ; pushing to the FPU stack
    cmp eax, 0
    je conv_err    
    jmp end_read

    conv_err:
        invoke StdOut, ADDR ConversionError
        invoke ExitProcess, 0
        
    end_read:
        ret
ReadInput endp


Sk proc, k:real10, x:real10
    fld1               ; +1 to the fpu's stack
    fld x               ; +2 to the fpu's stack
    fld k               ; +3 to the fpu's stack
    fadd st, st
    pow:
        ftst
        fstsw ax
        fwait
        sahf
        jna endpow
        fstp tmp        ; +2 to the fpu's stack
        fmul st(1), st
        fld tmp         ; +3 to the fpu's stack
        fld1            ; +4 to the fpu's stack
        fsubp st(1), st ; +3 to the fpu's stack
        jmp pow
    endpow:
    fstp st             ; +2 to the fpu's stack
    fstp st             ; +1 to the fpu's stack
    
    fld k               ; +2 to the fpu's stack
    fmul st, st
    fadd st, st
    fld1                ; +3 to the fpu's stack
    faddp st(1), st     ; +2 to the fpu's stack

    fmulp st(1), st     ; +1 to the fpu's stack
    

    fld k               ; +2 to the fpu's stack
    fadd st, st
    fld1

    fact:
        fstp tmp
        ftst
        fstsw ax
        fwait
        sahf
        jna endfact
        fld1
        fcomp
        fstsw ax
        fwait
        sahf
        jz endfact
        fld tmp
        fmul st, st(1)
        fld1            ; +4 to the fpu's stack
        fsubp st(2), st ; +3 to the fpu's stack
        jmp fact

    endfact:
        fstp st         ; +2 to the fpu's stack
        fld tmp

    fdivp st(1), st     ; +1 to the fpu's stack

    fld k
    lp:
        ftst
        fstsw ax
        fwait
        sahf
        jna endlp
        fstp tmp
        fchs
        fld tmp
        fld1
        fsubp st(1), st
        jmp lp
    endlp:
        fstp st

    ret
Sk endp


S proc, x:real10, n:real10
    fldz                        ; accumulator
    fldz                        ; counter
    
    lp1:
        fld n
        fcomp st(1)
        fstsw ax
        fwait
        sahf
        jb endlp1               ; if n is lower

        fstp tmp1               ; saving counter
        Invoke Sk, tmp1, x
        ;PrintSt0
        faddp st(1), st
        fld tmp1

        fld1
        faddp st(1), st
        jmp lp1
    endlp1:
        fstp st
    
    ret
S endp


Y proc, x:real10
    fld x           ; +1 to the fpu's stack
    fld x           ; +2 to the fpu's stack
    fmulp st(1), st ; +1 to the fpu's stack
    fld two         ; +2 to the fpu's stack
    fdivp st(1), st ; +1 to the fpu's stack
    fchs            ; change the sign of st
    fld one         ; +2 to the fpu's stack
    faddp st(1), st ; +1 to the fpu's stack
    fld x           ; +2 to the fpu's stack
    fcos
    fmulp st(1), st ; +1 to the fpu's stack
    fld x           ; +2 to the fpu's stack
    fld two         ; +3 to the fpu's stack
    fdivp st(1), st ; +2 to the fpu's stack
    fld x           ; +3 to the fpu's stack
    fsin
    fmulp st(1), st ; +2 to the fpu's stack
    fchs
    faddp st(1), st ; +1 to the fpu's stack

    end_y:
        ret
Y endp


MainProc proc
    fld a               ; current x value

    mainloop:
        fld b
        fcomp st(1)
        fstsw ax
        fwait
        sahf
        jb endmainloop

        fstp tmp2 
        fld tmp2
        PrintSt0
        invoke StdOut, addr Spaces
        invoke Y, tmp2
        PrintSt0

        fldz
        fstp counter
        lp2:
            invoke S, tmp2, counter
            fstp tmp3
            fld tmp3
            fsub st, st(1)
            fabs
            fld eps
            fcompp
            fstsw ax
            fwait
            sahf
            ja endlp2
            fld counter
            fld1
            faddp st(1), st
            fstp counter
            jmp lp2
        endlp2:
            fld tmp3
            Invoke StdOut, addr Spaces
            PrintSt0
            fld counter
            Invoke StdOut, addr Spaces
            PrintSt0Integer
            fstp st
            fstp st
            fstp st
        fld h
        faddp st(1), st
        Invoke StdOut, addr NewLine
        jmp mainloop

    endmainloop:
        ret
MainProc endp


start:
    invoke ReadInput
    invoke MainProc
    ;invoke Y, four
    ;PrintSt0
    ;invoke S, four, many
    ;PrintSt0    
    ;invoke CheckInput
    ;invoke CalculateD       ; +1 to the FPU stack
    ;invoke CheckD
    ;invoke CalculateRoots   ; +2 to the FPU stack
    ; invoke StdOut, addr X1EqTo
    ;PrintSt0
    ;invoke StdOut, addr NewLine
    ; invoke StdOut, addr X2EqTo
    ;fstp st                 ; -1 to the FPU stack
    ;PrintSt0
    invoke ExitProcess, 0

end start